
// verze 0.2 (po rozdeleni tridy Quzel na Qhrana a Qstrom)

#include "synt_an.h"
//#include "pamet.h"
//#include "struktio.h"
#include "beh.h"
#include "chyba.h"
#include "jadro.h"
#include "q_io.h"
#include "qconst.h"
#include "unif.h"
#include "xml.h"
//#include <dos.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define IDSPACES	1

//extern unsigned _stklen = 543210U;

int Chyba;

int alok=0;

void testdate()
{
/*  date d;
  getdate(&d);
  if(d.da_year>=2002) { puts("Interni chyba DE7"); exit(1); }
/**/}

void help() // anglicky help
{
  puts("\nQ systems, compiler & interpreter, version 1.012c\n");
  puts("QS <program file> <input file> [<output file>]\n - compiles and runs a program");
  puts("QS -t <program file>\n - syntax check of a program");
  puts("QS -ti <input file> [<output file>]\n - syntax check of a graph");
  puts("QS -c <program file> <compiled file>\n - compiles a program");
  puts("QS -b <input file> <output file> {program files}\n - runs programs");
  puts("QS -r <input file> <output file> {program files}\n - runs compiled programs");
  puts("QS -d <program file> <phase no.> <rule nr.> <chain>\n - reports about unification");
  puts("QS -m <input file> <output file> {program files}\n - compile programs");
  puts("\nSpecial options:");
  puts("-o - duplicate edges optimalization");
  puts("-s - no result output on the screen");
  puts("-e - exact graph cleaning");
  puts("-l - creates log file");
}

/*/void help() // cesky help
{
  puts("\nSystemy Q - kompilator & interpret, verze 1,012a\n");
  puts("QS <Q program> <vstupni soubor> [<vystupni soubor>]\n - zkompiluje a spusti program");
  puts("QS -t <Q program>\n - syntakticka kontrola programu");
  puts("QS -ti <vstupni soubor> [<vystupni soubor>]\n - syntakticka kontrola grafu");
  puts("QS -c <Q program> <zkompilovany soubor>\n - zkompiluje program");
  puts("QS -b <vstupni soubor> <vystupni soubor> {Q programy}\n - spusti programy");
  puts("QS -r <vstupni soubor> <vystupni soubor> {Q programy}\n - spusti zkompilovane programy");
  puts("QS -d <Q program> <cislo faze> <cislo pravidla> <retezec>\n - vypise zpravu o unifikaci");
  puts("QS -m <vstupni soubor> <vystupni soubor> {Q programy}\n - zkompiluje programy");
  puts("\nSpecialni prepinace:");
  puts("-o - optimalizace duplicitnich hran");
  puts("-s - nevypise vystupni graf na obrazovku");
  puts("-e - striktni mazani grafu");
  puts("-l - vytvori log soubor");
}/**/

int main(int argc,char** argv)
{
  testdate();
  int still=0,log=0;//,exact=1;
//  volnapamet("Uplny zacatek");
  if(argc>=2 && (!strcmp(argv[1],"/?") || !strcmp(argv[1],"-?") || !strcmp(argv[1],"-help")))
  { help(); return 0; }
  while(argc>=2 && (     !strcmp(argv[1],"-o")
                      || !strcmp(argv[1],"-s")
                      || !strcmp(argv[1],"-e")
                      || !strcmp(argv[1],"-l")
                 ))
  {
    if(!strcmp(argv[1],"-o")) Bunikat=1;
    if(!strcmp(argv[1],"-s")) still=1;
    if(!strcmp(argv[1],"-e")) Bprazdnygraf=1;
    if(!strcmp(argv[1],"-l")) log=1;
    for(int i=1;i<argc-1;i++) argv[i]=argv[i+1];
    argc--;
  }
  setCh(0);
  int rezim=0; // 0 - QS program vstup [vystup] (nacti program a proved ho)
	       // 1 - QS -t program (kontrola syntakticke spravnosti programu)
	       // 2 - QS -ti vstup [vystup] (kontrola syntakticke spravnosti vstupu)
	       // 3 - QS -b vstup vystup {programy} (provedeni vice programu)
	       // 4 - QS -c program vystup (kompilace)
	       // 5 - QS -r vstup vystup {programy} (provedeni zkompilovanych programu)
	       // 6 - QS -d program cislo_faze cislo_pravidla retezec (ladeni)
	       // 7 - QS -m vstup vystup {programy} (kompilace vice programu)
  if(argc>=2 && !strcmp(argv[1],"-t")) rezim=1;
  if(argc>=2 && !strcmp(argv[1],"-ti")) rezim=2;
  if(argc>=2 && !strcmp(argv[1],"-b")) rezim=3;
  if(argc>=2 && !strcmp(argv[1],"-c")) rezim=4;
  if(argc>=2 && !strcmp(argv[1],"-r")) rezim=5;
  if(argc>=2 && !strcmp(argv[1],"-d")) rezim=6;
  if(argc>=2 && !strcmp(argv[1],"-m")) rezim=7;
  if(argc>=2 && !strcmp(argv[1],"-xml")) rezim=8;
  QERR<<STR_TITLE<<endln<<STR_COPYRIGHT<<endln<<endln;
  //printf("!%d %d!", rezim, argc);
  if((rezim<=2 || rezim == 8) && argc<3 || rezim==3 && argc<5 || rezim>3 && rezim < 8 && argc<4 || rezim==6 && argc<6)
  { QERR<<STR_FEWARGUMENTS<<endln; return 1; }
  char *arg_program,*arg_vstup,*arg_vystup;
  int faze,pravidlo;
  switch(rezim)
  {
    case 0:
      arg_program=argv[1];
      arg_vstup=argv[2];
      if(argc>3) arg_vystup=argv[3]; else arg_vystup="test.out";
//      arg_vystup=(argc>3?argv[3]:"test.out");
      break;
    case 1:
      arg_program=argv[2];
      if(argc>3) arg_vystup=argv[3]; else arg_vystup=NULL;
      break;
    case 8:
	//puts("Case");
      arg_vstup=argv[2];
      if(argc>3) arg_vystup=argv[3]; else arg_vystup="test.xml";
//      arg_vystup=(argc>3?argv[3]:"test.out");
      break;
    case 2:
      arg_vstup=argv[2];
      if(argc>3) arg_vystup=argv[3]; else arg_vystup="test.out";
//      arg_vystup=(argc>3?argv[3]:"test.out");
      break;
    case 3:
      arg_vstup=argv[2];
      arg_vystup=argv[3];
      break;
    case 4:
      arg_program=argv[2];
      arg_vystup=argv[3];
      break;
    case 5:
      //arg_program=argv[2];
      arg_vstup=argv[2];
      arg_vystup=argv[3]; //(argc>4?argv[4]:"test.out");
      break;
    case 6:
      arg_program=argv[2];
      arg_vstup=argv[5];
      faze=atoi(argv[3]);
      pravidlo=atoi(argv[4]);
      break;
    case 7:
      arg_vstup=argv[2];
      arg_vystup=argv[3];
      break;
  }
  Qprogram* qp=NULL;
  if(rezim!=2 && rezim != 8)
  {
    //Lseznam* ls=NULL;
    if(rezim<=2 || rezim==4 || rezim==6)
    {
      QERR<<STR_ANALYZINGPROGRAMFILE<<" '"<<arg_program<<"'"<<endln;
      aktsoubor=arg_program;
      FILE* f=fopen(arg_program,"rt");
      if(!f) { QERR<<STR_CANNOTOPENFILE<<" '"<<arg_program<<"'"<<endln; return -1; }
  //    int usp;
 //     ls=nacti_program(f);
//      test_Lseznamu(ls);
//      if(!ls) { puts("Lexikalni analyza vratila nulovy spojak"); return -1; }
//      if(!usp) { puts("Lexikalni analyza selhala (mozna prilis dlouhy vstup)"); return -1; }
      Lmezery=IDSPACES;
      qp=synt_analyza(f);
      if(!qp) return -1; // added on March 10th (PH)
      fclose(f);
      //return 0;
    } else
      if(rezim==3 || rezim==7)
        for(int i=4;i<argc;i++)
        {
  	  QERR<<STR_ANALYZINGPROGRAMFILE<<" '"<<argv[i]<<"'"<<endln;
          aktsoubor=argv[i];
	  FILE* f=fopen(argv[i],"rt");
	  if(!f) { QERR<<STR_CANNOTOPENFILE<<" '"<<argv[i]<<"'"<<endln; if(qp) delete qp; return -1; }
          Qprogram* qp2=synt_analyza(f);
          fclose(f);
          if(i==4) qp=qp2; else qp->pripoj(qp2);
        } else
      if(rezim==5)
        for(int i=argc-1;i>=4;i--)
        {
  	  QERR<<STR_ANALYZINGPROGRAMFILE<<" '"<<argv[i]<<"'"<<endln;
          aktsoubor=argv[i];
	  FILE* f=fopen(argv[i],"rb");
	  if(!f) { QERR<<STR_CANNOTOPENFILE<<" '"<<argv[i]<<"'"<<endln; if(qp) delete qp; return -1; }
//	  int usp;
//	  Lseznam* ls2=nacti_program(f);
//	  test_Lseznamu(ls);
//	  ls=spoj_Lseznamy(ls,ls2);
	  if(i==argc-1) qp=new Qprogram(f); else qp->nacti(f);
	  if(!qp) return -1; // added on March 10th (PH)
	  fclose(f);
        }
    if(rezim<5 || rezim==7)
    {
      //qp=synt_analyza(ls);
      if(rezim==4 || rezim==7)
      {
	if(!qp) return -1;
	FILE* f=fopen(arg_vystup,"wb");
	if(!f) { QERR<<STR_CANNOTOPENFILE<<" '"<<arg_vystup<<"'"<<endln; delete qp; return -1; }
	//uloz_program(qp,f);
	qp->uloz(f);
	delete qp;
	fclose(f);
	QERR<<STR_COMPILEDSUCCESS<<endln;
//	smazspojakretezcu();
	return 0;
      }
    } /*else {
      FILE* f=fopen(arg_program,"rb");
      if(!f) { QERR<<STR_CANNOTOPENFILE<<" '"<<arg_program<<"'"<<endln; return -1; }
      //qp=cti_program(f);
      fclose(f);
    }/**/
//    printf("Delka spojaku lexemu: %d\n",delka_Lseznamu(ls));
    //volnapamet("Po syntakticke analyze");
    //smaz_Lseznam(ls);
    //volnapamet("Po smazani spojaku lexemu");
    if(!qp) return -1;
//    qp->test(stdout);
    if(rezim==1)
    {
      if(arg_vystup)
      {
        FILE* f=fopen(arg_vystup,"wt");
        if(!f) QERR<<STR_CANNOTOPENFILEOUT<<endln;
        else {
          QFILE.sethandle(f);
          qp->test(NULL);/**/
          fclose(f);
        }
      }
      //vypisretezcu();
      delete qp;
      QERR<<STR_COMPILEDSUCCESS<<endln;
//      //volnapamet("Po smazani syntakticke struktury");
//      smaz_Lseznam(ls);
      //volnapamet("Uplny konec");
//      smazspojakretezcu();
      return 0;
    }
  }

  if(rezim==6)
  {
    ladeni(qp,faze,pravidlo,arg_vstup);
    return 0;
  }

  Qvstup* qu;
  if(rezim!=1 && rezim!=4)
  {
	//puts("Entered");
    //volnapamet("Pred analyzou vstupu");
    QERR<<STR_ANALYZINGENTRYFILE<<" '"<<arg_vstup<<"'"<<endln<<endln;
    FILE* f=fopen(arg_vstup,"rt");
    if(!f) { QERR<<STR_CANNOTOPENFILE<<" '"<<arg_vstup<<"'"<<endln; return -1; }
    //volnapamet("Pred lexikalni analyzou");
    //Lseznam* ls=nacti_vstup(f);
    //volnapamet("Po lexikalni analyze");
    //fprintf(stderr,"c");
    qu=synt_vstup(f);
    //fprintf(stderr,"d");
    if(!qu) return -1; // added on March 10th (PH)
    fclose(f);
    //volnapamet("Po syntakticke analyze vstupu");
    //smaz_Lseznam(ls);
    //volnapamet("Po smazani spojaku lexemu");
//    if(!qu) return -1;
//    delete qu; //volnapamet("Po smazani syntakticke struktury"); exit(0);
    //volnapamet("Po vystupu na obrazovku");
    f=fopen(arg_vystup,"wt");
    if(!f) QERR<<STR_CANNOTOPENFILEOUT<<endln;
    else {
      QFILE.sethandle(f);
	//fprintf(stderr,"C");
	if (rezim == 8) qu->exportXml(f);
	//else qu->test2(NULL);
	//fprintf(stderr,"D");
	//puts("Written");
      	fclose(f);
	if (rezim == 8) {
		delete qu;
		return 0;
	}
    }
    if(rezim==2)
    {
      QFILE.sethandle(stdout);
	//fprintf(stderr,"A");
      qu->test1(NULL);
	//fprintf(stderr,"B");
      delete qu;
//      smazspojakretezcu();
      /*volnapamet("Uplny konec");/**/
      return 0;
    }
  }

//  Quzel* k=qu;
//  while(qu->vretez2()) qu=qu->vretez2();
//  while(k->vretez1()) k=k->vretez1();
// volnapamet("Pred behem");
//  beh(qu,k,qp);
//  QFILE.sethandle(stdout);
//  qp->test(NULL);
//  qu->test2(NULL);
  FILE* fl=NULL;
  if(log) fl=fopen("q.log","wt");
  qp->ocislovat();
//QFILE.sethandle(stdout);
//qp->test(NULL);
//getch();
  qp->beh(qu,(log ? fl : NULL));
  if(log && fl) fclose(fl);
//  qp->test(stdout);
  delete qp;
//  volnapamet("Po behu");

  QERR<<STR_OUTPUTTOFILE<<" '"<<arg_vystup<<"'"<<endln<<endln;
  if(qu) { // && qu->vhrana()){
//    volnapamet("Pred vypisem");
//    test2(stdout,0,qu);/*
    FILE* f=fopen(arg_vystup,"wt");
    if(Chyba) QERR<<STR_CANNOTOPENFILEOUT<<endln;
    if(!still)
    {
      QFILE.sethandle(stdout);
      qu->test1(stdout);/**/
    }
//    test2(f,0,qu);puts("");
    QFILE.sethandle(f);
    qu->test2(f);
    fclose(f);
//    volnapamet("Po vypisu - pred smazanim vystupu");
//    delete qu;
//    volnapamet("Po smazani vystupu");
  }else{
    if(!still)
      /*if(exact)*/ QIO<<STR_EMPTYGRAPH<<endln;
                 //else QIO<<STR_INPUTGRAPHUSED<<endln;
    //if(exact)
    {
      FILE* f=fopen(arg_vystup,"wt");
      if(Chyba) QERR<<STR_CANNOTOPENFILEOUT<<endln;
      QFILE.sethandle(f);
      QFILE<<STR_EMPTYGRAPH<<endln;
      fclose(f);
    }
  }
  delete qu; // added on March 10th (PH)

//  delete qp;
//  volnapamet("Uplny konec");
//  smazspojakretezcu();
  return 0;
}
